#ifndef DATA_AMOS_AFG_BAS_WRITER_H_
#define DATA_AMOS_AFG_BAS_WRITER_H_

#include <sstream>
#include "qvs/QualityValueVector.h"
using namespace std;

class AfgBasWriter {
    // TODO correct file type? outFile
    // TODO change SMRTSequence to FASTQ sequence? then maybe fasta2afg would be 
    // easier to write
    string afgFileName;
    ofstream afgOut;
    bool firstRecord;
    int recordCount;
    int defaultQuality;
    // Use 122 = '{' - 1 because '{' and '}' are the message delimiters in AMOS.
    static const unsigned char maxAfgQuality = 122; 
    static const unsigned char charToQuality = 48;
    static const unsigned char minAfgQuality = charToQuality + 1; 
    static const int lineLength = 80;

  private:

    unsigned char pacbioQVtoPhredQV(unsigned char pacbio){
        return (unsigned char) floor( 10.0 * log10( 1.0 + pow(10.0, pacbio / 100.0) ) + 0.5 );
    }
    
  public:
    ~AfgBasWriter() { 
        // Assume that closing the afg file must be done
        // manually and not in a destructor.
    }

    AfgBasWriter( ) {
        firstRecord = true;
        recordCount = 1;
        defaultQuality = 5;
    }

    void Initialize(string _afgFileName){
        afgFileName = _afgFileName;
        // CrucialOpen(afgFileName, afgOut, std::ios:out);
        CrucialOpen(afgFileName, afgOut);
    }

    void Close() {
        afgOut.close();
    }

    int Write(SMRTSequence &seq) {
        if (firstRecord){
            WriteHeader();
            firstRecord = false;
        }
        WriteOpen(seq);
        WriteIdentifier(seq);
        WriteBases(seq);
        WriteQualities(seq);
        WriteClose();
        return 1;
    }

    void SetDefaultQuality(int _defaultQuality){
        defaultQuality = _defaultQuality;
    }

  private:

    void WriteHeader(void){
        afgOut << "{UNV" << endl;
        afgOut << "iid:1" << endl;
        afgOut << "com:" << endl;
        afgOut << "generated by AfgBasWriter" << endl;
        afgOut << "Mon Jun 28 14:43:52 2010" << endl; // TODO put in real date
        afgOut << "." << endl << "}" << endl;
        afgOut << "{LIB" << endl << "iid:1" << endl;
        afgOut << "{DST" << endl << "mea:0" << endl << "std:0" << endl << "}" << endl << "}" << endl;
    }

    void WriteOpen(SMRTSequence &seq){
        afgOut << "{RED" << endl;
        afgOut << "frg:" << recordCount + 1 << endl;
        afgOut << "iid:" << recordCount << endl;
    }

    void WriteIdentifier(SMRTSequence &seq) {
        afgOut << "clr:0," << seq.length << endl;

        afgOut << "eid:";
        string fastaTitle;
        seq.GetFASTATitle(fastaTitle);
        afgOut << fastaTitle << endl;
    }

    void WriteClose(void){
        recordCount++;
        afgOut << "}" << endl;
        afgOut << "{FRG" << endl;
        afgOut << "iid:" << recordCount << endl;
        afgOut << "lib:1" << endl << "typ:I" << endl << "}" << endl;
        recordCount++;
    }

    void WriteBases(SMRTSequence &seq ) {
        afgOut << "seq:" << endl;
        ((DNASequence)seq).PrintSeq( afgOut, lineLength );
        afgOut << "." << endl;
    }

    void WriteQualities(SMRTSequence &seq) {
        afgOut << "qlt:" << endl;
        int i;
        for (i = 0; i < seq.length; i++ ){
            unsigned char quality =  seq.qual.data ?  seq.qual[i] : defaultQuality;
            quality = quality + charToQuality;
            quality = quality > maxAfgQuality ? maxAfgQuality : quality;
            quality = quality < minAfgQuality ? minAfgQuality : quality;
            afgOut << quality;
            if (i > 0 and (i+1) % lineLength == 0)
                afgOut << endl;
        }
        if (i == 0 or i % lineLength != 0) {
            afgOut << endl;
        }
        afgOut << "." << endl;
    }
};





#endif
